import datetime
import re
import logging

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.date import DateTrigger
from django.conf import settings
from django.contrib import auth
from django.contrib.auth import logout, login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.hashers import make_password
from django.http import JsonResponse, QueryDict, HttpResponseRedirect, HttpResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django.views.generic import TemplateView
from django.core.mail import send_mail
from django.utils.decorators import method_decorator

from custom import check_role
from system.models import UserProfile
from utils.captcha.captcha import captcha
from utils.common.request_handle import RouteSend
from utils.common.tools import random_nums, pwd_to_md5
from .forms import RegisterForm, LoginForm, ResetForm, ChangePasswordForm, ChangeEmailForm

logger = logging.getLogger(__name__)


def image_code(request, flag):
    """图片验证码"""
    name, text, image_data = captcha.generate_captcha()
    if flag == "register":
        request.session['register_image_code'] = text
    else:
        request.session['login_image_code'] = text

    return image_data


class ImageCodeView(View):
    """图片验证码"""

    def get(self, request):
        flag = request.GET.get('flag')

        image_data = image_code(request, flag)

        return HttpResponse(image_data, content_type="image/jpg")


class RegisterView(View):
    """注册视图"""

    def get(self, request):
        return render(request, 'users/register.html')

    def post(self, request):
        ret = {'code': 0, 'msg': '注册成功'}
        register_form = RegisterForm(request.POST)

        if register_form.is_valid():
            mobile = register_form.cleaned_data['mobile']
            email = register_form.cleaned_data['email']
            code = register_form.cleaned_data['image_code']
            password = register_form.cleaned_data['password']

            # 验证码
            image_code = request.session.get('register_image_code')
            if image_code.upper() != code.upper():
                ret['code'] = 10024
                ret['msg'] = '验证码错误'
                return JsonResponse(ret)

            # 创建新用户
            # new_user = UserProfile.objects.create_user(username=mobile, mobile=mobile, password=password, email=email)
            # new_user.save()

            password = pwd_to_md5(password)
            new_user = UserProfile.objects.create(username=mobile, mobile=mobile, password=password, email=email)
            new_user.save()

            # logger.info('%s 注册成功', email)
        else:
            # 字段验证有误
            pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
            errors = str(register_form.errors)
            register_form_errors = re.findall(pattern, errors)
            ret['code'] = 10001
            ret['msg'] = register_form_errors[0]

        return JsonResponse(ret)


class LoginView(View):
    """登陆视图"""

    def get(self, request):
        return render(request, 'users/login.html')

    def post(self, request):
        login_form = LoginForm(request.POST)
        ret = {'code': 0, 'msg': '登陆成功'}

        # 验证 form 表单
        if login_form.is_valid():
            mobile = login_form.cleaned_data['mobile']
            password = login_form.cleaned_data['password']
            code = login_form.cleaned_data['image_code']

            # 获取路由器 Mac 和 hmac
            mac = login_form.data.get('mac')
            hmac = login_form.data.get('hmac')

            # 验证码
            image_code = request.session.get('login_image_code')
            if image_code.upper() != code.upper():
                ret['code'] = 10024
                ret['msg'] = '验证码错误'
                return JsonResponse(ret)

            # user = auth.authenticate(username=mobile, password=password)
            #
            # if user:
            #     status = self.check_route_status(user, mac, hmac)  # 验证路由
            #     logger.info('登陆，验证路由：%s', status)
            #
            #     if status['code'] == 0:  # 在线
            #         login(request, user)
            #         request.session.set_expiry(7200)
            #     elif status['code'] == 10003:
            #         ret = {'code': 10003, 'msg': '路由器离线或不存在，是否继续登陆？'}
            #     elif status['code'] == 10005:
            #         ret = status
            #     else:
            #         ret = {'code': 10004, 'msg': '路由器不存在，请检查 Mac是否正确'}
            # else:
            #     ret = {'code': 10002, 'msg': '用户名或密码错误'}

            user = UserProfile.objects.filter(mobile=mobile).first()
            if user.password != pwd_to_md5(password):
                ret = {'code': 10002, 'msg': '用户名或密码错误'}
            else:
                status = self.check_route_status(user, mac, hmac)  # 验证路由
                logger.info('登陆，验证路由：%s', status)

                if status['code'] == 0:  # 在线
                    login(request, user)
                    request.session.set_expiry(7200)
                elif status['code'] == 10003:
                    ret = {'code': 10003, 'msg': '路由器离线或不存在，是否继续登陆？'}
                elif status['code'] == 10005:
                    ret = status
                else:
                    ret = {'code': 10004, 'msg': '路由器不存在，请检查 Mac是否正确'}

        else:
            # 字段验证有误
            pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
            errors = str(login_form.errors)
            login_form_errors = re.findall(pattern, errors)
            ret['code'] = 10001
            ret['msg'] = login_form_errors[0]

        return JsonResponse(ret)

    def check_route_status(self, user, mac, hmac):
        """检查路由设备是否在线"""
        ret = {'code': 0, 'msg': 'success'}
        rs = RouteSend()  # 实例化发送请求的类

        # 若 mac、hmac 存在，则开始校验路由器 Mac，mac 不存在直接登陆
        if all([mac, hmac]):
            check_mac_result = rs.check_mac(user, mac, hmac)  # 检查 Mac
            ret = rs.mac_resp_handle(check_mac_result, mac, hmac, user)  # 处理请求

        return ret


class ReLoginView(View):
    """重新登录"""

    def post(self, request):
        login_form = LoginForm(request.POST)
        ret = {'code': 10001, 'msg': '字段验证有问题'}

        if login_form.is_valid():
            mobile = login_form.cleaned_data['mobile']
            password = login_form.cleaned_data['password']

            # user = auth.authenticate(username=mobile, password=password)
            user = UserProfile.objects.filter(mobile=mobile).first()

            if user:
                login(request, user)
                request.session.set_expiry(7200)

                ret = {'code': 0, 'msg': '登陆成功'}

        return JsonResponse(ret)


class LogoutView(View):
    """登出"""

    def get(self, request):
        logout(request)
        return redirect(reverse('login'))


@method_decorator(login_required, name='get')
@method_decorator(check_role, name='get')
class ProfileView(TemplateView):
    """个人信息页"""

    template_name = 'users/profile.html'


class ResetView(View):
    """忘记密码"""

    def get(self, request):
        return render(request, 'users/reset.html')

    def post(self, request):
        ret = {'code': 0, 'msg': '重置成功'}
        code = request.POST.get('code')

        # 验证码是否为空
        if not code:
            ret = {'code': 10018, 'msg': '验证码不能为空'}
            return JsonResponse(ret)

        reset_form = ResetForm(request.POST)
        if reset_form.is_valid():
            email = reset_form.cleaned_data['email']
            password = reset_form.cleaned_data['password']

            # 判断邮箱是否存在
            user = UserProfile.get_user(email)
            if not user:
                return JsonResponse({'code': 10016, 'msg': '邮箱不存在'})

            # 验证码是否正确
            if code != request.session.get('valid_code'):
                return JsonResponse({'code': 10019, 'msg': '验证码不正确'})

            # 更新数据库
            # password = make_password(password)
            password = pwd_to_md5(password)
            UserProfile.objects.filter(email=email).update(password=password)

            # user.update(**{'password': password})
            logger.info('%s 忘记密码修改成功', email)

        else:
            # 字段验证有误
            pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
            errors = str(reset_form.errors)
            reset_form_errors = re.findall(pattern, errors)
            ret['code'] = 10017
            ret['msg'] = reset_form_errors[0]

        return JsonResponse(ret)


class SendEmailView(View):
    """发送邮箱验证码"""

    def get(self, request):
        ret = {'code': 0, 'msg': '发送成功'}

        email = request.GET.get('email', None)
        if email:
            # 验证邮箱是否存在
            user = UserProfile.get_user(email)
            if not user:
                return JsonResponse({'code': 10016, 'msg': '邮箱不存在'})

            # 生成随机验证码
            code = random_nums()

            try:
                # 发送邮箱验证码
                send_mail(
                    subject=settings.SUBJECT,
                    message=settings.MESSAGE.format(code),
                    from_email=settings.EMAIL_HOST_USER,
                    recipient_list=[email],
                    fail_silently=False
                )

                # 将验证码写入 session 中
                request.session['valid_code'] = code

                # 定时任务，1min 后删除验证码
                sched = BackgroundScheduler()
                start = datetime.datetime.now()
                tt = (start + datetime.timedelta(seconds=180)).strftime('%Y-%m-%d %H:%M:%S')
                sched.add_job(self.delete_code, run_date=tt, args=[request])
                sched.start()

            except Exception as e:
                logger.error('发送邮件出错：%s', e)
                ret = {'code': 10020, 'msg': '邮件发送失败'}
        else:
            ret = {'code': 10015, 'msg': '邮箱不能为空'}

        return JsonResponse(ret)

    def delete_code(self, request):
        """删除 session 中的验证码"""

        del request.session['valid_code']


@method_decorator(login_required, name='post')
class ChangePasswordView(View):
    """修改密码"""

    def post(self, request):
        ret = {'code': 0, 'msg': '修改成功'}
        user = request.user

        change_password_form = ChangePasswordForm(request.POST)
        if change_password_form.is_valid():
            origin_password = change_password_form.cleaned_data['origin_password']
            password = change_password_form.cleaned_data['password']
            confirm_password = change_password_form.cleaned_data['confirm_password']

            # 验证原始密码是否正确
            # if not user.check_password(origin_password):
            #     ret['code'] = 10022
            #     ret['msg'] = '原始密码错误'
            #     return JsonResponse(ret)

            user_obj = UserProfile.objects.filter(id=user.id).first()

            if user_obj.password != pwd_to_md5(origin_password):
                ret['code'] = 10022
                ret['msg'] = '原始密码错误'
                return JsonResponse(ret)

            # 前后两次密码是否一致
            if password != confirm_password:
                ret['code'] = 10023
                ret['msg'] = '两次密码不一致'
                return JsonResponse(ret)

            # 更新数据库
            # user.set_password(password)
            # user.save()

            UserProfile.objects.filter(id=user.id).update(password=pwd_to_md5(password))
            logger.info('%s 修改密码成功', request.user)
        else:
            # 字段验证有误
            pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
            errors = str(change_password_form.errors)
            change_password_form_errors = re.findall(pattern, errors)
            ret['code'] = 10021
            ret['msg'] = change_password_form_errors[0]

        return JsonResponse(ret)


@method_decorator(login_required, name='post')
class EmailUpdateView(View):
    """修改邮箱"""

    def post(self, request):
        ret = {'code': 0, 'msg': '修改成功'}
        user = request.user

        email_form = ChangeEmailForm(request.POST)
        if email_form.is_valid():
            new_email = email_form.cleaned_data['new_email']

            # 更新数据库
            UserProfile.objects.filter(id=user.id).update(**{'email': new_email})
            logger.info('%s 邮箱修改成功', user)
        else:
            # 字段验证有误
            pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
            errors = str(email_form.errors)
            email_form_errors = re.findall(pattern, errors)
            ret['code'] = 10021
            ret['msg'] = email_form_errors[0]

        return JsonResponse(ret)
